package disco;

import java.lang.reflect.InvocationTargetException;
import java.util.Hashtable;
import java.lang.Math;
import java.util.Date;
import java.util.Enumeration;
//import java.util.logging.Level;
//import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import tiempo.Temporizador;

public class Disco implements Runnable{
    //Son constantes para todas las busquedas
    final int tiempoTransferencia = 0;
    final int velocidadCabezal = 0;

    /*
     * Estos seran inicializadas por el constructor cuando
     * se tengan los valores de la interfaz
     */
    int rpm;
    int numPistas;
    int sectoresPorPista;
    int posicionCabezal; //Dice en que pista esta el cabezal.
    
    /*
     * Lleva el conteo de cuantas pistas se han recorrido para satisfacer las
     * peticiones de un proceso
     * <pid, resumenProceso>
     */
    Hashtable<Integer,ResumenProceso> tablaPidResumenProceso = new Hashtable<Integer,ResumenProceso>();


    
public Disco(int numPistas, int sectoresPorPista){
    this.rpm = rpm;
    this.numPistas = numPistas;
    this.sectoresPorPista = sectoresPorPista;
    //Main.cabezal = 0;
}

private void moverCabezal(int nextPista, int pid){
        try {
            int distanciaRecorrida = Math.abs(nextPista - Main.cabezal);
            final String toAppendMoverCabezal = "Posicion inicial del cabezal: " + Main.cabezal + "\nPosicion final del cabezal (prox): " + nextPista + "\nDistancia recorrida: " + distanciaRecorrida;
//            System.out.println(toAppend1);
            //Se actualiza el numero de pistas de un proceso
            tablaPidResumenProceso.get(pid).numPistas = tablaPidResumenProceso.get(pid).numPistas + distanciaRecorrida;
            Main.cabezal = nextPista;
            final String toAppendMoverCabezal2 = "\nResumenProceso del proceso pid=" + pid + ": " + tablaPidResumenProceso.get(pid).toString() + "\n______________________________________________________________________________";
//            System.out.println(toAppend2);
//            Thread.sleep(Main.tiempoSleep);

            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    //Tercer textArea.
                    disco.Main.actualizarPeticionesDiscoGui(toAppendMoverCabezal + toAppendMoverCabezal2);
                }
            });
        } catch (InterruptedException ex) {
            Logger.getLogger(Disco.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvocationTargetException ex) {
            Logger.getLogger(Disco.class.getName()).log(Level.SEVERE, null, ex);
        }
}

private int calcularPista(int sector){
    int pista = sector / this.sectoresPorPista;
    return pista;
}

public synchronized void manejarPeticiones(){
   for (int i = 0; i < Main.dispatchQueue.listaPeticiones.size(); i++){
        CFQRequest peticion = Main.dispatchQueue.get();
        Date fecha = new Date();
        ResumenProceso resumenProceso = new ResumenProceso();
        peticion.tiempoAtencion = fecha.getTime() - (Main.tiempoComienzoApp + peticion.tiempoPeticion);

        //Actualizar el tiempo de atencion de un proceso
        if (tablaPidResumenProceso.containsKey(peticion.pid)){
            resumenProceso = tablaPidResumenProceso.get(peticion.pid);
            resumenProceso.tiempoAtencion = resumenProceso.tiempoAtencion + peticion.tiempoAtencion;//TODO promedio
        }else{
            resumenProceso.tiempoAtencion = peticion.tiempoAtencion;
        }
        resumenProceso.numPeticiones++;
        tablaPidResumenProceso.put(peticion.pid, resumenProceso);
        moverCabezal(calcularPista(peticion.bloque), peticion.pid);
        calcularPromedios();
                Temporizador.sleep();
   }
}

private void calcularPromedios(){
        try {
            /* Los promedios que se deben calcular son:
            pistasTotal;//Sumatoria de pistas recorridas por todos los procesos
            tiempoTotal;//Tiempo total de la simulacion
            promPistas;//Entre todos los procesos
            promTiempo;//Entre todos los procesos
             *
            tiempoAtencion; //Suma de todos los tiempos de atencion de las peticiones que involucran este proceso
            numPistas;//Totales por proceso
            numPeticiones;//Totales por proceso
             */
            final String toAppendCalcularPromedios;
            Date fecha = new Date();
            long tiempoFinApp = fecha.getTime();
            ResumenProceso.tiempoTotal = tiempoFinApp - Main.tiempoComienzoApp;
            int numProcesos = 0;
            float sumatoriaTiempos = 0;
            ResumenProceso.pistasTotal = 0;
            Enumeration iteradorHash = tablaPidResumenProceso.keys();
            while (iteradorHash.hasMoreElements()) {
                numProcesos++;
                Object key = iteradorHash.nextElement();
                ResumenProceso resumenProceso = tablaPidResumenProceso.get(key);
                ResumenProceso.pistasTotal += resumenProceso.numPistas;
                sumatoriaTiempos += resumenProceso.tiempoAtencion;
            }
            ResumenProceso.promPistas = ResumenProceso.pistasTotal / numProcesos;
            ResumenProceso.promTiempo = sumatoriaTiempos / numProcesos;
            toAppendCalcularPromedios = "Numero total de pistas recorridas: "
                + ResumenProceso.pistasTotal
                + "\nTiempo total de todas las peticiones en milisegundos: "
                + ResumenProceso.tiempoTotal
                + "\nPromedio de pistas recorridas para satisfacer las peticiones por proceso: "
                + ResumenProceso.promPistas
                + "\nPromedio de tiempo de atencion por proceso en milisegundos: "
                + ResumenProceso.promTiempo
                + "\n\n\n\n______________________________________________________________________________";

//            System.out.println(toAppend);
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    disco.Main.actualizarResumenGui(toAppendCalcularPromedios);
                }
            });
        } catch (InterruptedException ex) {
            Logger.getLogger(Disco.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvocationTargetException ex) {
            Logger.getLogger(Disco.class.getName()).log(Level.SEVERE, null, ex);
        }
  }

  public int getCabezal(){
    return Main.cabezal;
  }

public void run(){
    while(true){
            manejarPeticiones();
    }
}
}
